#include "https.h"
#include <curl/curl.h>


string https::https_request(const string& httpMethod, 
                            const string& url) const
{
    user_data userData = {NULL, -1, ""};

    return https_request(httpMethod, url, generalHeaders, userData);
}


string https::https_request(const string& httpMethod, 
                            const string& url,
                            const vector<string>& customHeaders) const
{
    user_data userData = {NULL, -1, ""};

    return https_request(httpMethod, url, customHeaders, userData);
}

string https::https_request(const string& httpMethod, 
                            const string& url,
                            const user_data& userData) const
{
    return https_request(httpMethod, url, generalHeaders, userData);
}

string https::https_request(const string& httpMethod, 
                            const string& url,
                            const vector<string>& customHeaders,
                            const user_data& userData) const
{
   string respBuffer;           //response from the server
   char *fileBuffer = NULL;     //content in a file
   CURL *curl = NULL;           //https connection handle

   curl = curl_easy_init();
   if (curl)
   {
       char errorBuffer[CURL_ERROR_SIZE];

       curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errorBuffer);
       curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
       curl_easy_setopt(curl, CURLOPT_HEADER, 0);
       curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
       curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_to_buf);
       curl_easy_setopt(curl, CURLOPT_WRITEDATA, &respBuffer);
       curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
       curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0l);
       //curl_easy_setopt(curl, );

       struct curl_slist *headers = NULL;
       vector<string>::iterator iter;

       //add general headers
       for (iter = generalHeaders.begin(); iter != generalHeaders.end(); iter++)
           headers = curl_slist_append(headers, (*iter).c_str());

       //add custom headers
       for (iter = customHeaders.begin(); iter != customHeaders.end(); iter++)
           headers = curl_slist_append(headers, (*iter).c_str());

       //add the headers into request
       curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);

       //configuration for different methods
       if (httpMethod == "GET")
       {
           curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L);
           
       }
       else if (httpMethod == "POST")
       {
           curl_easy_setopt(curl, CURLOPT_POST, 1);

           if (userData.size == -1 )//read data from a file
           {
               ifstream file(userData.fileName.c_str(), ios::binary | ios:ate);

               if (!file)
               {
                   cerr<<"Cannot open file "<<userData.fileName<<endl;
                   return respBuffer;
               }
               else
               {
                   int fileSize = static_cast<int>(file.tellg());
                   fileBuffer = new char[fileSize];
                   file.seekg(0, ios::beg);
                   file.read(fileBuffer, fileSize);
                   file.close();

                   curl_easy_setopt(curl, CURLOPT_POSTFIELDS, fileBuffer);
                   curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, fileSize);
               }
           }
           else
           {
               curl_easy_setopt(curl, CURLOPT_POSTFIELDS, userData.content);
               curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, userData.size);
           }

       }
       else if (httpMethod == "PUT")
       {
           curl_easy_setopt(curl, CURLOPT_PUT, 1L); 
       }
       else if (httpMethod == "DELETE")
       {
           curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE"); 
       }
       else
       {
           cerr<<"Undefined http method:"<<httpMethod<<endl;
           exit(1);
       }

       //perform the request
       CURLcode curlCode = curl_easy_perform(curl);

       int httpCode = 0;
       curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode);

       //clean up
       curl_easy_cleanup(curl);
       curl_slist_free_all(headers);
       if (fileBuffer != NULL)
       {
           delete []fileBuffer;
       }

       //return status
       if (curlCode != CURLE_OK)
       {
           cerr<<"Curl error: No."<<curlCode<<" - "<<errorBuffer<<endl;
           exit(1);
       }
       else if (httpCode => 400)
       {
           cerr<<"Http error:"<<httpCode<<" response"<<endl
               <<respBuffer<<endl;
           exit(1);
       }

   }

   return respBuffer;
}

size_t https::write_to_buf(char* data, 
                           size_t size, 
                           size_t nmemb,
                           string* buffer)
{
    size_t dataLen = size * nmemb;
    if (buffer != NULL)
    {
        buffer->append(data, realsize);
    }
    else
    {
        cerr<<"Null pointer of buffer"<<endl;
    }

    return dataLen;

}
